import type { Data, AsyncDataResult, PaginationQuery } from '../define/types'
import crud from './crud'
import query from './query'
import _ from 'lodash'
import { primaryKey, toSqliteTypes } from '../utils'
import table from '../impl/table'
import type IEntity from '../define/entity'
import { v4Id } from '../utils'

class Entity implements IEntity {
  private tableName: string

  constructor(tableName: string) {
    this.tableName = tableName
  }

  async _checkTable(data: Data) {
    let _data: any = _.isArray(data) && !_.isEmpty(data) ? data[0] : data
    const tableExists = await table.exists(this.tableName)

    if (!tableExists) { 
      const columns = toSqliteTypes(_data)
      await table.create(this.tableName, columns)
    }
  }

  async save(data: Data): AsyncDataResult {
    await this._checkTable(data)
    const idField = primaryKey()
    data = _.isArray(data) ? data : [data]
    data.forEach((item: any) => {
      item[idField] = v4Id()
    })
    await crud.insert(this.tableName, data)
  }

  async update(data: any): AsyncDataResult {
    const idField = primaryKey()
    const conditions = { [idField]: data[idField] }
    return await crud.update(this.tableName, conditions, data)
  }

  async drop(id: string): AsyncDataResult<string> {
    const idField = primaryKey()
    const conditions = { [idField]: id }
    return await crud.drop(this.tableName, conditions)
  }

  async page(pager: PaginationQuery): AsyncDataResult {
    const size = pager.size ?? 10
    const offset = pager.no ? (pager.no - 1) * size : 0
    return await query.select(
      this.tableName,
      pager.where || {},
      size,
      offset,
      pager.orderBy || []
    )
  }
}

export default Entity
